﻿#include "connectingwindow.h"
#include "nodewidget.h"
#include <QLabel>
#include <QGridLayout>
#include <QPainter>
#include <QPen>
#include <QButtonGroup>
#include <QtDebug>

/**
 * @brief ConnectingWindow::ConnectingWindow
 * @details 构造连接窗口并初始化节点布局与信号绑定。
 * @param type 硬件模板类型。
 * @param parent Qt 父对象。
 */
ConnectingWindow::ConnectingWindow(HardwareTemplateType type, QWidget *parent)
    : QWidget(parent)
    , m_buttonGroup(new QButtonGroup(this))
    , m_type(type)
{
    setMinimumSize(790, 560);
    mainLayout = new QGridLayout(this);
    mainLayout->setContentsMargins(0, 0, 0, 0);

    // 基本节点
    m_SIG = new NodeWidget(DeviceRole::SignalGenerator, this);
    m_PA = new NodeWidget(DeviceRole::Amplifier, this);

    m_FWD_PM = new NodeWidget(DeviceRole::PowerMeterForward, this);
    m_REV_PM = new NodeWidget(DeviceRole::PowerMeterReverse, this);
    m_MON_PM = new NodeWidget(DeviceRole::PowerMeterMonitor, this);
    m_MON_Receiver = new NodeWidget(DeviceRole::Receiver, this);

    // 连接器节点
    m_dbSIG2PA = new NodeWidget(DeviceRole::Connector_SIG2PA, this);
    m_dbFWD2PM = new NodeWidget(DeviceRole::Connector_FWD2PM, this);
    m_dbREV2PM = new NodeWidget(DeviceRole::Connector_REV2PM, this);
    m_dbPA2Transducers = new NodeWidget(DeviceRole::Connector_PA2Transducers, this);
    m_dbTransducers2PM = new NodeWidget(DeviceRole::Connector_Transducers2PM, this);

    QList<NodeWidget *> allNodes {m_SIG, m_PA, m_FWD_PM, m_REV_PM, m_MON_PM, m_MON_Receiver,
                                  m_dbSIG2PA, m_dbFWD2PM, m_dbREV2PM, m_dbPA2Transducers, m_dbTransducers2PM};

    if (m_type == HardwareTemplateType::CS) {
        m_CIP_Input = new NodeWidget(DeviceRole::CurrentInjectionProbeInput, this);
        m_CIP_Monitor = new NodeWidget(DeviceRole::CurrentInjectionProbeMonitor, this);
        allNodes << m_CIP_Input << m_CIP_Monitor;
        initUI_CS();
    } else {
        m_RadANT = new NodeWidget(DeviceRole::AntennaRadiates, this);
        m_RecANT = new NodeWidget(DeviceRole::AntennaReceives, this);
        m_FD = new NodeWidget(DeviceRole::FieldProbe, this);
        allNodes << m_FD << m_RadANT << m_RecANT;
        initUI_RS();
    }

    mainLayout->setColumnStretch(0, 1);
    mainLayout->setColumnStretch(1, 1);
    mainLayout->setColumnStretch(2, 1);
    mainLayout->setColumnStretch(3, 1);
    mainLayout->setColumnStretch(4, 1);
    mainLayout->setColumnStretch(5, 1);
    mainLayout->setColumnStretch(6, 0);
    mainLayout->setColumnStretch(7, 1);

    for (NodeWidget *node : allNodes) {
        QToolButton *btn = node->getButton();
        btn->installEventFilter(this);
        m_watchedLabels.insert(btn);
        connect(node, &NodeWidget::sig_itemChanged, this, &ConnectingWindow::slot_itemChanged);
        connect(btn, &QToolButton::toggled, this, &ConnectingWindow::slot_nodeToggled);
        m_buttonGroup->addButton(btn);
        m_btn2Node.insert(btn, node);
    }
    m_SIG->getButton()->setChecked(true);
    QPalette pal = palette();
    pal.setColor(QPalette::Window, QColor("#303135"));
    setPalette(pal);
}

/**
 * @brief ConnectingWindow::~ConnectingWindow
 * @details 默认析构，Qt 自动清理子对象。
 */
ConnectingWindow::~ConnectingWindow()
{
}

/**
 * @brief ConnectingWindow::initUI_RS
 * @details 初始化辐射测试布局，配置节点与连接。
 */
void ConnectingWindow::initUI_RS()
{
    QFrame *tmp = new QFrame(this);
    tmp->setFixedWidth(20);
    mainLayout->addWidget(m_SIG, 0, 0, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_dbSIG2PA, 0, 1, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_PA, 0, 2, 1, 2, Qt::AlignCenter);
    mainLayout->addWidget(m_dbPA2Transducers, 0, 4, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_RadANT, 0, 5, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(tmp, 0, 6, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_RecANT, 0, 7, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_FD, 0, 7, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_dbFWD2PM, 1, 2, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_dbTransducers2PM, 1, 7, 1, 1, Qt::AlignCenter);

    mainLayout->addWidget(m_dbREV2PM, 2, 3, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_MON_PM, 2, 7, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_MON_Receiver, 2, 7, 1, 1, Qt::AlignCenter);

    mainLayout->addWidget(m_FWD_PM, 3, 2, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_REV_PM, 3, 3, 1, 1, Qt::AlignCenter);

    m_connections.append({m_SIG->getButton(), m_dbSIG2PA->getButton()});
    m_connections.append({m_dbSIG2PA->getButton(), m_PA->getButton()});
    m_connections.append({m_PA->getButton(), m_dbPA2Transducers->getButton()});
    m_connections.append({m_PA->getButton(), m_dbFWD2PM->getButton()});
    m_connections.append({m_PA->getButton(), m_dbREV2PM->getButton()});

    m_connections.append({m_dbFWD2PM->getButton(), m_FWD_PM->getButton()});
    m_connections.append({m_dbREV2PM->getButton(), m_REV_PM->getButton()});

    m_connections.append({m_dbPA2Transducers->getButton(), m_RadANT->getButton()});

    m_RadANT->setEnabled(false);
    m_RecANT->hide();
    m_dbTransducers2PM->hide();
    m_MON_PM->hide();
    m_MON_Receiver->hide();
}

/**
 * @brief ConnectingWindow::initUI_CS
 * @details 初始化传导测试布局，配置节点与连接。
 */
void ConnectingWindow::initUI_CS()
{
    mainLayout->addWidget(m_SIG, 0, 0, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_dbSIG2PA, 0, 1, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_PA, 0, 2, 1, 2, Qt::AlignCenter);
    mainLayout->addWidget(m_dbPA2Transducers, 0, 4, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_CIP_Input, 0, 6, 1, 1, Qt::AlignCenter);

    mainLayout->addWidget(m_dbFWD2PM, 1, 2, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_CIP_Monitor, 1, 6, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_dbTransducers2PM, 1, 7, 1, 1, Qt::AlignCenter);

    mainLayout->addWidget(m_dbREV2PM, 2, 3, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_MON_PM, 2, 7, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_MON_Receiver, 2, 7, 1, 1, Qt::AlignCenter);

    mainLayout->addWidget(m_FWD_PM, 3, 2, 1, 1, Qt::AlignCenter);
    mainLayout->addWidget(m_REV_PM, 3, 3, 1, 1, Qt::AlignCenter);

    m_connections.append({m_SIG->getButton(), m_dbSIG2PA->getButton()});
    m_connections.append({m_dbSIG2PA->getButton(), m_PA->getButton()});
    m_connections.append({m_PA->getButton(), m_dbPA2Transducers->getButton()});
    m_connections.append({m_PA->getButton(), m_dbFWD2PM->getButton()});
    m_connections.append({m_PA->getButton(), m_dbREV2PM->getButton()});

    m_connections.append({m_dbFWD2PM->getButton(), m_FWD_PM->getButton()});
    m_connections.append({m_dbREV2PM->getButton(), m_REV_PM->getButton()});

    m_connections.append({m_dbPA2Transducers->getButton(), m_CIP_Input->getButton()});
    m_connections.append({m_CIP_Input->getButton(), m_CIP_Monitor->getButton()});
    m_connections.append({m_CIP_Monitor->getButton(), m_dbTransducers2PM->getButton()});
    m_connections.append({m_dbTransducers2PM->getButton(), m_MON_PM->getButton()});
    m_CIP_Input->setEnabled(false);
}

/**
 * @brief ConnectingWindow::setSubRangeName
 * @details 设置子频段名称。
 * @param subRangeName 名称字符串。
 */
void ConnectingWindow::setSubRangeName(const QString &subRangeName)
{
    m_subRangeName = subRangeName;
}

/**
 * @brief ConnectingWindow::setData
 * @details 将硬件模板数据加载到节点控件。
 * @param hwTemplate 模板指针。
 */
void ConnectingWindow::setData(const HardwareTemplatePtr &hwTemplate)
{
    if (!hwTemplate)
        return;
    m_loading = true;
    m_hwTemplateData = hwTemplate; // 关键：持有同一份指针
    m_templateID = hwTemplate->id;

    auto set_node = [&](NodeWidget *n, const DeviceConfigBasePtr &cfg) {
        if (!n)
            return;
        const QString m = cfg ? cfg->gAttributes.Model : STR_NO_DEVICE;
        n->setDevice(m);
    };
    set_node(m_SIG, m_hwTemplateData->d_Generator);
    set_node(m_PA, m_hwTemplateData->d_Amplifier);
    set_node(m_FWD_PM, m_hwTemplateData->d_FwdPowerMeter);
    set_node(m_REV_PM, m_hwTemplateData->d_RevPowerMeter);
    set_node(m_dbSIG2PA, m_hwTemplateData->c_SIG2PA);
    set_node(m_dbFWD2PM, m_hwTemplateData->c_FWD2PM);
    set_node(m_dbREV2PM, m_hwTemplateData->c_REV2PM);
    set_node(m_dbPA2Transducers, m_hwTemplateData->c_PA2Transducers);
    set_node(m_dbTransducers2PM, m_hwTemplateData->c_Transducers2PM);

    if (m_hwTemplateData->d_MonPowerMeter->gAttributes.Model != STR_NO_DEVICE)
        set_node(m_MON_PM, m_hwTemplateData->d_MonPowerMeter);
    else
        set_node(m_MON_Receiver, m_hwTemplateData->d_MonReceiver);

    if (m_type == HardwareTemplateType::RS) {
        const bool isAnt = (hwTemplate->d_ReceivesAntenna->gAttributes.Model == STR_DEVICE_TYPE_GeneralAntenna);
        if (isAnt) {
            set_node(m_RecANT, hwTemplate->d_ReceivesAntenna);
        } else {
            set_node(m_FD, hwTemplate->d_MonFieldProbes);
        }
        // m_RecANT->setVisible(isAnt);
        // m_dbTransducers2PM->setVisible(isAnt);
        // m_FD->setVisible(!isAnt);
    } else {
        set_node(m_CIP_Input, hwTemplate->d_InjectionTransducer);
        set_node(m_CIP_Monitor, hwTemplate->d_MonitoringTransducer);
    }

    m_SIG->getButton()->setChecked(true);

    m_loading = false;
    update();
}

/**
 * @brief ConnectingWindow::getHardwareTemplate
 * @details 返回内部模板引用，供外部同步。
 * @return 模板指针引用。
 */
HardwareTemplatePtr &ConnectingWindow::getHardwareTemplate()
{
    return m_hwTemplateData;
}

/**
 * @brief ConnectingWindow::templateId
 * @details 获取当前模板 ID。
 * @return 模板编号。
 */
int ConnectingWindow::templateId() const
{
    return m_templateID;
}

/**
 * @brief ConnectingWindow::getCurrentDeviceRole
 * @details 返回当前激活的设备角色。
 * @return 设备角色。
 */
DeviceRole ConnectingWindow::getCurrentDeviceRole() const
{
    return m_curRole;
}

/**
 * @brief ConnectingWindow::uncheckAllToolButtons
 * @details 取消所有节点按钮的选中状态。
 */
void ConnectingWindow::uncheckAllToolButtons()
{
    m_buttonGroup->setExclusive(false);
    for (auto *b : m_buttonGroup->buttons())
        b->setChecked(false);
    m_buttonGroup->setExclusive(true);
}

/**
 * @brief ConnectingWindow::clearDevieRole
 * @details 重置记录的角色状态。
 */
void ConnectingWindow::clearDevieRole()
{
    m_preRole = DeviceRole::Undefined;
    m_curRole = DeviceRole::Undefined;
}

/**
 * @brief ConnectingWindow::slot_itemChanged
 * @details 节点型号变更时处理可见性与连线调整。
 * @param item 新型号。
 */
void ConnectingWindow::slot_itemChanged(const QString &item)
{
    NodeWidget *wid = static_cast<NodeWidget *>(sender());
    QStringList list = wid->getDeviceList();
    if (m_type == HardwareTemplateType::RS) {
        if (wid == m_RecANT || wid == m_FD) {
            (wid == m_RecANT ? m_FD : m_RecANT)->setDevice(item);
            bool isGeneralAntenna = (item == STR_DEVICE_TYPE_GeneralAntenna);

            // 显示/隐藏相关组件
            m_FD->setVisible(!isGeneralAntenna);
            m_RecANT->setVisible(isGeneralAntenna);
            m_dbTransducers2PM->setVisible(isGeneralAntenna);
            bool isReceiver = (m_hwTemplateData->d_MonReceiver->gAttributes.Model != STR_NO_DEVICE) ? true : false;

            // 管理连接
            if (isGeneralAntenna) {
                m_curRole = DeviceRole::AntennaReceives;
                m_RecANT->getButton()->setChecked(true);
                list = m_RecANT->getDeviceList();
                m_MON_PM->setVisible(!isReceiver);
                m_MON_Receiver->setVisible(isReceiver);
                m_connections.append({m_RecANT->getButton(), m_dbTransducers2PM->getButton()});
                if (isReceiver)
                    m_connections.append({m_dbTransducers2PM->getButton(), m_MON_Receiver->getButton()});
                else
                    m_connections.append({m_dbTransducers2PM->getButton(), m_MON_PM->getButton()});
            } else {
                m_MON_PM->setVisible(isGeneralAntenna);
                m_MON_Receiver->setVisible(isGeneralAntenna);
                m_MON_PM->setDevice(STR_NO_DEVICE);
                m_MON_Receiver->setDevice(STR_NO_DEVICE);

                m_curRole = DeviceRole::FieldProbe;
                m_FD->getButton()->setChecked(true);
                list = m_FD->getDeviceList();
                m_connections.removeOne({m_RecANT->getButton(), m_dbTransducers2PM->getButton()});
                m_connections.removeOne({m_dbTransducers2PM->getButton(), m_MON_PM->getButton()});
                m_connections.removeOne({m_dbTransducers2PM->getButton(), m_MON_Receiver->getButton()});
            }
        }
    }
    DeviceRole role = wid->getDeviceRole();
    if (role == DeviceRole::Receiver || role == DeviceRole::PowerMeterMonitor) {
        m_curRole = role;
        DeviceRole targetRole = DataManager::instance()->getDeiceRoleForModel(item);
        if (m_curRole != targetRole) {
            if (targetRole == DeviceRole::Receiver) {
                m_MON_Receiver->setDevice(item);
                m_MON_Receiver->setVisible(true);
                list = m_MON_Receiver->getDeviceList();
                m_MON_Receiver->getButton()->setChecked(true);
                m_MON_PM->setVisible(false);
                m_connections.append({m_dbTransducers2PM->getButton(), m_MON_Receiver->getButton()});
            } else {
                m_connections.append({m_dbTransducers2PM->getButton(), m_MON_PM->getButton()});
                m_MON_PM->setDevice(item);
                m_MON_PM->setVisible(true);
                m_MON_PM->getButton()->setChecked(true);
                list = m_MON_PM->getDeviceList();
                m_MON_Receiver->setVisible(false);
            }
        }
    }
    if (role >= DeviceRole::Connector_SIG2PA && role <= DeviceRole::Connector_Transducers2PM) {
        bool isAtt = (item == STR_NO_DEVICE) ? true : false;
        wid->setConnectorIconImage(isAtt);
        wid->setDevice(item);
    }

    emit sig_syncModel(list, item);
}

/**
 * @brief ConnectingWindow::slot_nodeToggled
 * @details 节点按钮选中状态变化时通知外部。
 * @param checked 是否选中。
 */
void ConnectingWindow::slot_nodeToggled(bool checked)
{
    auto *btn = qobject_cast<QToolButton *>(sender());
    NodeWidget *wid = m_btn2Node.value(btn, nullptr);
    if (!wid)
        return;

    wid->setFocus();
    m_curRole = wid->getDeviceRole();
    emit sig_nodeToggled(m_curRole, checked);
    emit sig_syncModel(wid->getDeviceList(), wid->getDevice());
}

/**
 * @brief ConnectingWindow::paintEvent
 * @details 绘制节点之间的连线。
 * @param event 绘制事件。
 */
void ConnectingWindow::paintEvent(QPaintEvent *event)
{
    QWidget::paintEvent(event);
    QPainter painter(this);
    QPen pen(Qt::white, 2);
    painter.setPen(pen);
    painter.setRenderHint(QPainter::Antialiasing, true);

    for (const auto &c : m_connections) {
        auto *a = c.first;
        auto *b = c.second;
        if (!a->isVisible() || !b->isVisible())
            continue;
        QPoint p1 = a->mapTo(this, a->rect().center());
        QPoint p2 = b->mapTo(this, b->rect().center());
        painter.drawLine(p1, p2);
    }
}

/**
 * @brief ConnectingWindow::eventFilter
 * @details 监听节点位置变化以刷新连线。
 * @param watched 被监听对象。
 * @param event 事件指针。
 * @return 是否拦截事件。
 */
bool ConnectingWindow::eventFilter(QObject *watched, QEvent *event)
{
    if (m_watchedLabels.contains(watched)) {
        if (event->type() == QEvent::Move || event->type() == QEvent::Resize) {
            update();
        }
    }
    return QWidget::eventFilter(watched, event);
}

/**
 * @brief ConnectingWindow::hasConnection
 * @details 判断两节点之间是否已存在连线。
 */
bool ConnectingWindow::hasConnection(QToolButton *a, QToolButton *b) const
{
    for (const auto &p : m_connections) {
        if ((p.first == a && p.second == b) || (p.first == b && p.second == a))
            return true;
    }
    return false;
}

/**
 * @brief ConnectingWindow::addConnection
 * @details 添加两节点之间的连线。
 */
void ConnectingWindow::addConnection(QToolButton *a, QToolButton *b)
{
    if (!hasConnection(a, b))
        m_connections.append({a, b});
}

/**
 * @brief ConnectingWindow::removeConnection
 * @details 移除两节点之间的连线。
 */
void ConnectingWindow::removeConnection(QToolButton *a, QToolButton *b)
{
    for (int i = 0; i < m_connections.size(); ++i) {
        auto &p = m_connections[i];
        if ((p.first == a && p.second == b) || (p.first == b && p.second == a)) {
            m_connections.removeAt(i);
            --i;
        }
    }
}
